﻿using Framework.Caching.FreeRedis;
using Framework.Core.Attributes;
using Framework.Core.Consts;
using Framework.Core.Enums;
using Framework.SqlSugarCore.Repositories;
using Mapster;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using my.abp.Domain.IManagers.Menu;
using my.abp.Domain.IManagers.Org;
using my.abp.Domain.IManagers.Role;
using my.abp.Domain.IManagers.User;
using my.abp.Domain.Managers.Role;
using my.abp.Domain.Managers.User;
using my.abp.Domain.Repositories.Menu;
using my.abp.Domain.Repositories.User;
using my.abp.Domain.Shared.Entities;
using my.abp.Domain.Shared.Enums;
using NUglify;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Services;
using Volo.Abp.Uow;

namespace my.abp.Domain.Managers.Menu
{
	public class SysMenuManager : DomainService, ISysMenuManager
	{
		private readonly ISysMenuRepository _SysMenuRepository;
		private Framework.AspNetCore.User.CurrentUser _CurrentUser;
		private readonly ISysUserRoleManager _sysUserRoleManager;
		private readonly ISysRoleMenuManager _sysRoleMenuManager;
		private readonly IWantDistributedCache _sysCache;
		private readonly ISysUserRoleRepository _sysUserRoleRep;

		public SysMenuManager(ISysMenuRepository SysMenuRepository, ISysUserRoleManager sysUserRoleManager, IWantDistributedCache sysCache,
			ISysRoleMenuManager sysRoleMenuManager, Framework.AspNetCore.User.CurrentUser currentUser, ISysUserRoleRepository sysUserRoleRep) 
		{
			_SysMenuRepository = SysMenuRepository;
			_sysUserRoleManager = sysUserRoleManager;
			_sysRoleMenuManager = sysRoleMenuManager;
			_CurrentUser = currentUser;
			_sysCache = sysCache;
			_sysUserRoleRep = sysUserRoleRep;
		}

		public async Task<List<long>> GetList(List<long> MenuIdList)
		{
			var queryable = await _SysMenuRepository.AsQueryable();
			// 将父节点为0的菜单排除，防止前端全选异常
			var pMenuIds = await queryable.Where(u => MenuIdList.Contains(u.Id) && u.Pid == 0).ToListAsync(u => u.Id);
			return MenuIdList.Except(pMenuIds).ToList(); // 差集
		}

		/// <summary>
		/// 获取登录菜单树
		/// </summary>
		/// <returns></returns>
		public async Task<List<SysMenu>> GetLoginMenuTree()
		{
			var queryable = await _SysMenuRepository.AsQueryable();
			if (_CurrentUser.SuperAdmin)
			{
				return await queryable
					.Where(u => u.Type != MenuTypeEnum.Btn && u.Status == StatusEnum.Enable)
					.OrderBy(u => new { u.OrderNo, u.Id }).ToTreeAsync(u => u.Children, u => u.Pid, 0);
			}
			else
			{
				var menuIdList = await GetMenuIdList();
				List<SysMenu> menuTree = await queryable
					.Where(u => u.Status == StatusEnum.Enable)
					.OrderBy(u => new { u.OrderNo, u.Id }).ToTreeAsync(u => u.Children, u => u.Pid, 0, menuIdList.Select(d => (object)d).ToArray());
				DeleteBtnFromMenuTree(menuTree);
				return menuTree;
			}
		}

		/// <summary>
		/// 删除登录菜单树里面的按钮
		/// </summary>
		private void DeleteBtnFromMenuTree(List<SysMenu> menuList)
		{
			if (menuList == null) return;
			for (var i = menuList.Count - 1; i >= 0; i--)
			{
				var menu = menuList[i];
				if (menu.Type == MenuTypeEnum.Btn)
					menuList.Remove(menu);
				else if (menu.Children.Count > 0)
					DeleteBtnFromMenuTree(menu.Children);
			}
		}

		/// <summary>
		/// 获取当前用户菜单Id集合
		/// </summary>
		/// <returns></returns>
		private async Task<List<long>> GetMenuIdList()
		{
			if (_CurrentUser.Id == null) return null;
			var roleIdList = await _sysUserRoleManager.GetUserRoleIdList(_CurrentUser.UserId);
			return await _sysRoleMenuManager.GetRoleMenuIdList(roleIdList);
		}

		public async Task<List<SysMenu>> GetList(SysMenu input)
		{
			var menuIdList = _CurrentUser.SuperAdmin ? new List<long>() : await GetMenuIdList();

			if (menuIdList == null) return null;
			var queryable = await _SysMenuRepository.AsQueryable();
			// 有筛选条件时返回list列表（防止构造不出树）
			if (!string.IsNullOrWhiteSpace(input.Title) || input.Type is > 0)
			{
				return await queryable
					.WhereIF(!string.IsNullOrWhiteSpace(input.Title), u => u.Title.Contains(input.Title))
					.WhereIF(input.Type is > 0, u => u.Type == input.Type)
					.WhereIF(menuIdList.Count > 1, u => menuIdList.Contains(u.Id))
					.OrderBy(u => u.OrderNo).ToListAsync();
			}

			return _CurrentUser.SuperAdmin ?
				await queryable.OrderBy(u => u.OrderNo).ToTreeAsync(u => u.Children, u => u.Pid, 0) :
				await queryable.OrderBy(u => u.OrderNo).ToTreeAsync(u => u.Children, u => u.Pid, 0, menuIdList.Select(d => (object)d).ToArray()); // 角色菜单授权时
		}

		public async Task AddMenu(SysMenu input)
		{
			var isExist = input.Type != MenuTypeEnum.Btn
				? await _SysMenuRepository.IsAnyAsync(u => u.Title == input.Title)
				: await _SysMenuRepository.IsAnyAsync(u => u.Permission == input.Permission);

			if (isExist)
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D4000));

			// 校验菜单参数
			var sysMenu = input.Adapt<SysMenu>();
			CheckMenuParam(sysMenu);

			await _SysMenuRepository.InsertAsync(sysMenu);

			// 清除缓存
			DeleteMenuCache();
		}

		/// <summary>
		/// 增加和编辑时检查菜单数据
		/// </summary>
		/// <param name="menu"></param>
		private static void CheckMenuParam(SysMenu menu)
		{
			var permission = menu.Permission;
			if (menu.Type == MenuTypeEnum.Btn)
			{
				menu.Name = null;
				menu.Path = null;
				menu.Component = null;
				menu.Icon = null;
				menu.Redirect = null;
				menu.OutLink = null;
				menu.IsHide = false;
				menu.IsKeepAlive = true;
				menu.IsAffix = false;
				menu.IsIframe = false;

				if (string.IsNullOrEmpty(permission))
					throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D4003));
				if (!permission.Contains(':'))
					throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D4004));
			}
			else
			{
				menu.Permission = null;
			}
		}

		/// <summary>
		/// 清除菜单和按钮缓存
		/// </summary>
		private void DeleteMenuCache()
		{
			_sysCache.Remove<List<string>, string>(CacheConst.KeyUserMenu + "0", CacheConst.cacheName);
			_sysCache.Remove<List<string>, string>(CacheConst.KeyUserButton + "0", CacheConst.cacheName);
		}

		/// <summary>
		/// 更新菜单
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task UpdateMenu(SysMenu input)
		{
			if (input.Id == input.Pid)
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D4008));

			var isExist = input.Type != MenuTypeEnum.Btn
				? await _SysMenuRepository.IsAnyAsync(u => u.Title == input.Title && u.Type == input.Type && u.Id != input.Id)
				: await _SysMenuRepository.IsAnyAsync(u => u.Permission == input.Permission && u.Type == input.Type && u.Id != input.Id);
			if (isExist)
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D4000));

			// 校验菜单参数
			var sysMenu = input.Adapt<SysMenu>();
			CheckMenuParam(sysMenu);

			var updateable = await _SysMenuRepository.AsUpdateable(sysMenu);
			await updateable.ExecuteCommandAsync();

			// 清除缓存
			DeleteMenuCache();
		}

		/// <summary>
		/// 删除菜单
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		[UnitOfWork]
		public async Task DeleteMenu(SysMenu input)
		{
			var queryable = await _SysMenuRepository.AsQueryable();
			var menuTreeList = await queryable.ToChildListAsync(u => u.Pid, input.Id, true);
			var menuIdList = menuTreeList.Select(u => u.Id).ToList();

			await _SysMenuRepository.DeleteAsync(u => menuIdList.Contains(u.Id));

			// 级联删除角色菜单数据
			await _sysRoleMenuManager.DeleteRoleMenuByMenuIdList(menuIdList);

			// 清除缓存
			DeleteMenuCache();
		}

		/// <summary>
		/// 获取用户拥有按钮权限集合（缓存）
		/// </summary>
		/// <returns></returns>
		public async Task<List<string>> GetOwnBtnPermList()
		{
			var userId = _CurrentUser.UserId;
			var permissions = _sysCache.Get<List<string>, string>(CacheConst.KeyUserButton + userId,CacheConst.cacheName);
			if (permissions == null || permissions.Count == 0)
			{
				var menuIdList = _CurrentUser.SuperAdmin ? new List<long>() : await GetMenuIdList();
				permissions = await _SysMenuRepository.GetOwnBtnPermList(menuIdList);
				_sysCache.Set(CacheConst.KeyUserButton + userId, permissions, CacheConst.cacheName);
			}
			return permissions;
		}

		/// <summary>
		/// 获取系统所有按钮权限集合（缓存）
		/// </summary>
		/// <returns></returns>
		public async Task<List<string>> GetAllBtnPermList()
		{
			var permissions = _sysCache.Get<List<string>, string>(CacheConst.KeyUserButton + 0, CacheConst.cacheName);
			if (permissions == null || permissions.Count == 0)
			{
				permissions = await _SysMenuRepository.GetAllBtnPermList();
				_sysCache.Set(CacheConst.KeyUserButton + "0", permissions, CacheConst.cacheName);
			}
			return permissions;
		}
	}
}
